package com.xxl.job.admin.core.thread;

import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.xxl.job.admin.core.model.XxlJobLogReport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * job log report helper
 *
 * @author xuxueli 2019-11-22
 */
public class JobLogReportHelper {

  private static Logger logger = LoggerFactory.getLogger(JobLogReportHelper.class);

  private static JobLogReportHelper instance = new JobLogReportHelper();

  public static JobLogReportHelper getInstance() {
    return instance;
  }


  private Thread logrThread;
  private volatile boolean toStop = false;

  public void start() {
    logrThread = new Thread(new Runnable() {

      @Override
      public void run() {

        // last clean log time
        long lastCleanLogTime = 0;

        while (!toStop) {

          // 1、log-report refresh: refresh log report in 3 days
          try {

            for (int i = 0; i < 3; i++) {

              // today
              Calendar itemDay = Calendar.getInstance();
              itemDay.add(Calendar.DAY_OF_MONTH, -i);
              itemDay.set(Calendar.HOUR_OF_DAY, 0);
              itemDay.set(Calendar.MINUTE, 0);
              itemDay.set(Calendar.SECOND, 0);
              itemDay.set(Calendar.MILLISECOND, 0);

              Date todayFrom = itemDay.getTime();

              itemDay.set(Calendar.HOUR_OF_DAY, 23);
              itemDay.set(Calendar.MINUTE, 59);
              itemDay.set(Calendar.SECOND, 59);
              itemDay.set(Calendar.MILLISECOND, 999);

              Date todayTo = itemDay.getTime();

              // refresh log-report every minute
              XxlJobLogReport xxlJobLogReport = new XxlJobLogReport();
              xxlJobLogReport.setTriggerDay(todayFrom);
              xxlJobLogReport.setRunningCount(0);
              xxlJobLogReport.setSucCount(0);
              xxlJobLogReport.setFailCount(0);

              Map<String, Object> triggerCountMap = XxlJobAdminConfig.getAdminConfig()
                  .getXxlJobLogDao().findLogReport(todayFrom, todayTo);
              if (triggerCountMap != null && triggerCountMap.size() > 0) {
                int triggerDayCount =
                    triggerCountMap.containsKey("triggerDayCount") ? Integer.valueOf(
                        String.valueOf(triggerCountMap.get("triggerDayCount"))) : 0;
                int triggerDayCountRunning =
                    triggerCountMap.containsKey("triggerDayCountRunning") ? Integer.valueOf(
                        String.valueOf(triggerCountMap.get("triggerDayCountRunning"))) : 0;
                int triggerDayCountSuc =
                    triggerCountMap.containsKey("triggerDayCountSuc") ? Integer.valueOf(
                        String.valueOf(triggerCountMap.get("triggerDayCountSuc"))) : 0;
                int triggerDayCountFail =
                    triggerDayCount - triggerDayCountRunning - triggerDayCountSuc;

                xxlJobLogReport.setRunningCount(triggerDayCountRunning);
                xxlJobLogReport.setSucCount(triggerDayCountSuc);
                xxlJobLogReport.setFailCount(triggerDayCountFail);
              }

              // do refresh
              int ret = XxlJobAdminConfig.getAdminConfig().getXxlJobLogReportDao()
                  .update(xxlJobLogReport);
              if (ret < 1) {
                XxlJobAdminConfig.getAdminConfig().getXxlJobLogReportDao().save(xxlJobLogReport);
              }
            }

          } catch (Exception e) {
            if (!toStop) {
              logger.error(">>>>>>>>>>> xxl-job, job log report thread error:{}", e);
            }
          }

          // 2、log-clean: switch open & once each day
          if (XxlJobAdminConfig.getAdminConfig().getLogretentiondays() > 0
              && System.currentTimeMillis() - lastCleanLogTime > 24 * 60 * 60 * 1000) {

            // expire-time
            Calendar expiredDay = Calendar.getInstance();
            expiredDay.add(Calendar.DAY_OF_MONTH,
                -1 * XxlJobAdminConfig.getAdminConfig().getLogretentiondays());
            expiredDay.set(Calendar.HOUR_OF_DAY, 0);
            expiredDay.set(Calendar.MINUTE, 0);
            expiredDay.set(Calendar.SECOND, 0);
            expiredDay.set(Calendar.MILLISECOND, 0);
            Date clearBeforeTime = expiredDay.getTime();

            // clean expired log
            List<Long> logIds = null;
            do {
              logIds = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao()
                  .findClearLogIds(0, 0, clearBeforeTime, 0, 1000);
              if (logIds != null && logIds.size() > 0) {
                XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().clearLog(logIds);
              }
            } while (logIds != null && logIds.size() > 0);

            // update clean time
            lastCleanLogTime = System.currentTimeMillis();
          }

          try {
            TimeUnit.MINUTES.sleep(1);
          } catch (Exception e) {
            if (!toStop) {
              logger.error(e.getMessage(), e);
            }
          }

        }

        logger.info(">>>>>>>>>>> xxl-job, job log report thread stop");

      }
    });
    logrThread.setDaemon(true);
    logrThread.setName("xxl-job, admin JobLogReportHelper");
    logrThread.start();
  }

  public void toStop() {
    toStop = true;
    // interrupt and wait
    logrThread.interrupt();
    try {
      logrThread.join();
    } catch (InterruptedException e) {
      logger.error(e.getMessage(), e);
    }
  }

}
